#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "syntax.h"
#include "symbol.h"
#include "tools.h"

void initFunction(FILE *fp_out, char *name, char *type);
int analyseCompUnit(FILE *fp_in, FILE *fp_out);
void analyseGlobalVarDef(FILE *fp_in, FILE *fp_out);
void analyseFuncDef(FILE *fp_in, FILE *fp_out);
void analyseBlock(FILE *fp_in, FILE *fp_out, int mode);     // 0:不带{}; 1:带{}
void analyseBlockItem(FILE *fp_in, FILE *fp_out);
void analyseDecl(FILE *fp_in, FILE *fp_out);
void analyseConstDef(FILE *fp_in, FILE *fp_out);
void analyseVarDef(FILE *fp_in, FILE *fp_out);
void analyseStmt(FILE *fp_in, FILE *fp_out);
Inter_var *analyseCond(FILE *fp_in, FILE *fp_out);
Inter_var *analyseLOrExp(FILE *fp_in, FILE *fp_out);
Inter_var *analyseLAndExp(FILE *fp_in, FILE *fp_out);
Inter_var *analyseEqExp(FILE *fp_in, FILE *fp_out);
Inter_var *analyseRelExp(FILE *fp_in, FILE *fp_out);
Inter_var *analyseExp(FILE *fp_in, FILE *fp_out, int mode);
Inter_var *analyseFuction(FILE *fp_in, FILE *fp_out, char name[]);
void specify(FILE *fp_out, int mode, Inter_var vars[], int *top_var, enum operator opt);
void printLLVM(FILE *fp_out, Inter_var vars[], int *top_var, char *str, Inter_var a, Inter_var b);
void printCondLLVM(FILE *fp_out, char *str, Inter_var *a, Inter_var *b);

void syntaxAnalysis(char *file_input, char *file_output) {
    // 打开文件
    FILE *fp_in, *fp_out;
    if ((fp_in = fopen(file_input, "r")) == NULL) {
        printf("File open error!\n");
        exit(-1);
    }
    if ((fp_out = fopen(file_output, "w")) == NULL) {
        printf("File open error!\n");
        exit(-1);
    }

    // 数据结构初始化
    memset(hold, '\0', sizeof(hold));
    table_global->zone[++(table_global->top_zone)] = 0;     // 栈底为全局变量的开始
    initFunction(fp_out, "getint", "int");
    initFunction(fp_out, "getch", "int");
    initFunction(fp_out, "putint", "void");
    initFunction(fp_out, "putch", "void");

    // 逐行读入语法分析
    fscanf(fp_in, "%s", hold);
    while(strlen(hold) != 0) {
        int flag_decl = 1;

        // CompUnit语法判断
        while (isCompUnitBegin(hold) && flag_decl) {
            flag_decl = analyseCompUnit(fp_in, fp_out);
        }

        if (strlen(hold) !=0 ) {
            printf("Wrong start!\n");
            exit(2);    // 语法错误
        }
    }

    // 关闭文件
    fclose(fp_in);
    fclose(fp_out);
}

void initFunction(FILE *fp_out, char *name, char *type) {
    Ident *ident = (Ident *)malloc(sizeof(Ident));
    strcpy(ident->name, name);
    strcpy(ident->type, type);
    ident->address = -1;
    ident->def = 2;
    if (strcmp(type, "int") == 0) { fprintf(fp_out, "declare i32 @%s()\n", name); }
    if (strcmp(type, "void") == 0) { fprintf(fp_out, "declare void @%s(i32)\n", name); }
    insertItem(ident, table_global);
}

bool isCompUnitBegin(char str[]) {
    return isDeclBegin(str) || isFuncBegin(str);
}

bool isFuncDefBegin(char str[]) {
    return (strcmp(str, "Int") == 0);
}

bool isBlockItemBegin(char str[]) {
    return isDeclBegin(str) || isStmtBegin(str);
}

bool isDeclBegin(char str[]) {
    return (strcmp(str, "Const") == 0) || (strcmp(str, "Int") == 0);
}

bool isStmtBegin(char str[]) {
    return (strcmp(str, "Return") == 0) 
    || isIdentBegin(str) || isExpBegin(str) 
    || (strcmp(str, "Semicolon") == 0)
    || (strcmp(str, "If") == 0)
    || (strcmp(str, "LBrace") == 0);
}

bool isIdentBegin(char str[]) {
    return (strncmp(str, "Ident", 5) == 0);
}

bool isFuncBegin(char str[]) {
    if (strncmp(str, "Ident", 5) == 0) {
        char temp[MAXLEN];
        strcpy(temp, str);
        slice(temp, 6, strlen(temp)-2);
        Ident *ident = findGlobalItem(temp, table_global);
        if (ident->def == 2)
            return 1;
    } 
    return 0;
}

bool isExpBegin(char str[]) {
    return isNumber(str) || isIdentBegin(str) || (strcmp(hold, "LBrace") == 0) || (strcmp(hold, "Minus") == 0) || (strcmp(hold, "Plus") == 0);
}

int analyseCompUnit(FILE *fp_in, FILE *fp_out) {
    // ConstDecl
    if (strcmp(hold, "Const") == 0) {
        memset(hold, '\0', sizeof(hold));
        fscanf(fp_in, "%s", hold);

        // Btype
        if (strcmp(hold, "Int") != 0) {
            exit(2);   // 语法错误
        }
        memset(hold, '\0', sizeof(hold));
        fscanf(fp_in, "%s", hold);

        // ConstDef
        if (isIdentBegin(hold)) {
            analyseConstDef(fp_in, fp_out);
        } else {
            exit(2);   // 语法错误
        }

        while (strcmp(hold, "Comma") == 0) {
            memset(hold, '\0', sizeof(hold));
            fscanf(fp_in, "%s", hold);
            if (isIdentBegin(hold)) {
                analyseConstDef(fp_in, fp_out);
            } else {
                exit(2);   // 语法错误
            }
        }

        // ';'
        if (strcmp(hold, "Semicolon") != 0) {
            exit(2);   // 语法错误
        }
        memset(hold, '\0', sizeof(hold));
        fscanf(fp_in, "%s", hold);
    }
    // VarDecl & FuncDef
    else {
        memset(hold, '\0', sizeof(hold));
        fscanf(fp_in, "%s", hold);

        // FuncDef
        if (strcmp(hold, "Ident(main)") == 0) {
            analyseFuncDef(fp_in, fp_out);
            return 0;
        }

        // VarDecl
        else {
            if (isIdentBegin(hold)) {
            analyseGlobalVarDef(fp_in, fp_out);
            } else {
                exit(2);   // 语法错误
            }

            while (strcmp(hold, "Comma") == 0) {
                memset(hold, '\0', sizeof(hold));
                fscanf(fp_in, "%s", hold);
                if (isIdentBegin(hold)) {
                    analyseGlobalVarDef(fp_in, fp_out);
                } else {
                    exit(2);   // 语法错误
                }
            }

            // ';'
            if (strcmp(hold, "Semicolon") != 0) {
                exit(2);   // 语法错误
            }
            memset(hold, '\0', sizeof(hold));
            fscanf(fp_in, "%s", hold);
        }
    }
    
    return 1;
}

/* type & name already read and checked */
void analyseFuncDef(FILE *fp_in, FILE *fp_out) {
    
    fprintf(fp_out, "define dso_local i32 ");

    // Ident
    if (strncmp(hold, "Ident", 5) == 0) {
        slice(hold, 6, strlen(hold)-2);
        fprintf(fp_out, "@%s ", hold);
    } else {
        exit(2);   // 语法错误
    }
    memset(hold, '\0', sizeof(hold));
    fscanf(fp_in, "%s", hold);

    // '('
    if (strcmp(hold, "LPar") == 0 ) {
        fprintf(fp_out, "(");
    } else {
        exit(2);   // 语法错误
    }
    memset(hold, '\0', sizeof(hold));
    fscanf(fp_in, "%s", hold);

    // ')'
    if (strcmp(hold, "RPar") == 0 ) {
        fprintf(fp_out, ")");
    } else {
        exit(2);   // 语法错误
    }
    memset(hold, '\0', sizeof(hold));
    fscanf(fp_in, "%s", hold);
    
    // Block
    analyseBlock(fp_in, fp_out, 1);
}

void analyseGlobalVarDef(FILE *fp_in, FILE *fp_out) {
    // Ident
    slice(hold, 6, strlen(hold)-2);

    // 符号表操作
    if (isInTable(hold, table_global)) {        
        printf("Global ident exist!\n");
        exit(3);    // 语义错误
    }
    Ident *ident = (Ident *)malloc(sizeof(Ident));
    strcpy(ident->name, hold);
    strcpy(ident->type, "int");
    ident->address = -1;
    ident->value = 0;
    ident->def = 3;     // 全局变量
    insertItem(ident, table_global);

    memset(hold, '\0', sizeof(hold));
    fscanf(fp_in, "%s", hold);

    if (strcmp(hold, "Assign") == 0) {
        memset(hold, '\0', sizeof(hold));
        fscanf(fp_in, "%s", hold);
        Inter_var *result = analyseExp(fp_in, fp_out, 1);
        ident->value = result->value;
    } else {
        ident->value = 0;
    }
    fprintf(fp_out, "@%s = dso_local global i32 %d\n", ident->name, ident->value);
}

void analyseBlock(FILE *fp_in, FILE *fp_out, int mode) {
    // 符号表作用域更新
    table_global->zone[++(table_global->top_zone)] = table_global->top_list + 1;

    // '{'
    if (strcmp(hold, "LBrace") == 0 ) {
        if (mode) { fprintf(fp_out, "{\n"); }
    } else {
        exit(2);   // 语法错误
    }
    memset(hold, '\0', sizeof(hold));
    fscanf(fp_in, "%s", hold);
    
    while (isBlockItemBegin(hold)) {
        // BlockItem
        analyseBlockItem(fp_in, fp_out);
    }
    
    // '}'
    if (strcmp(hold, "RBrace") == 0 ) {
        if (mode) { fprintf(fp_out, "}"); }
    } else {
        exit(2);   // 语法错误
    }
    memset(hold, '\0', sizeof(hold));
    fscanf(fp_in, "%s", hold);

    // 符号表作用域更新
    table_global->top_list = table_global->zone[(table_global->top_zone)] - 1;
    table_global->top_zone--;
}

void analyseBlockItem(FILE *fp_in, FILE *fp_out) {
    // Decl
    if (isDeclBegin(hold)) {
        analyseDecl(fp_in, fp_out);
    }

    // Stmt
    else {
        analyseStmt(fp_in, fp_out);
    }
}

void analyseDecl(FILE *fp_in, FILE *fp_out) {
    // ConstDecl
    if (strcmp(hold, "Const") == 0) {
        memset(hold, '\0', sizeof(hold));
        fscanf(fp_in, "%s", hold);

        // Btype
        if (strcmp(hold, "Int") != 0) {
            exit(2);   // 语法错误
        }
        memset(hold, '\0', sizeof(hold));
        fscanf(fp_in, "%s", hold);

        // ConstDef
        if (isIdentBegin(hold)) {
            analyseConstDef(fp_in, fp_out);
        } else {
            exit(2);   // 语法错误
        }

        while (strcmp(hold, "Comma") == 0) {
            memset(hold, '\0', sizeof(hold));
            fscanf(fp_in, "%s", hold);
            if (isIdentBegin(hold)) {
                analyseConstDef(fp_in, fp_out);
            } else {
                exit(2);   // 语法错误
            }
        }

        // ';'
        if (strcmp(hold, "Semicolon") != 0) {
            exit(2);   // 语法错误
        }
        memset(hold, '\0', sizeof(hold));
        fscanf(fp_in, "%s", hold);
    }

    // VarDecl
    else {
        // Btype
        if (strcmp(hold, "Int") != 0) {
            exit(2);   // 语法错误
        }
        memset(hold, '\0', sizeof(hold));
        fscanf(fp_in, "%s", hold);

        // VarDef
        if (isIdentBegin(hold)) {
            analyseVarDef(fp_in, fp_out);
        } else {
            exit(2);   // 语法错误
        }

        while (strcmp(hold, "Comma") == 0) {
            memset(hold, '\0', sizeof(hold));
            fscanf(fp_in, "%s", hold);
            if (isIdentBegin(hold)) {
                analyseVarDef(fp_in, fp_out);
            } else {
                exit(2);   // 语法错误
            }
        }

        // ';'
        if (strcmp(hold, "Semicolon") != 0) {
            exit(2);   // 语法错误
        }
        memset(hold, '\0', sizeof(hold));
        fscanf(fp_in, "%s", hold);
    }
}

void analyseConstDef(FILE *fp_in, FILE *fp_out) {
    // Ident
    slice(hold, 6, strlen(hold)-2);
    if (isInTable(hold, table_global)) {        // 符号表操作
        printf("Ident exist!\n");
        exit(3);    // 语义错误
    }
    Ident *ident = (Ident *)malloc(sizeof(Ident));
    strcpy(ident->name, hold);
    strcpy(ident->type, "int");
    ident->address = -1;
    ident->value = 0;
    ident->def = 1;
    insertItem(ident, table_global);
    memset(hold, '\0', sizeof(hold));
    fscanf(fp_in, "%s", hold);

    // '='
    if (strcmp(hold, "Assign") != 0) {
        printf("Const def error!\n");
        exit(2);    // 语法错误
    }
    memset(hold, '\0', sizeof(hold));
    fscanf(fp_in, "%s", hold);

    // ConstInitVal
    Inter_var *result = analyseExp(fp_in, fp_out, 1);
    ident->address = -1;
    ident->value = result->value;
}

void analyseVarDef(FILE *fp_in, FILE *fp_out) {
    // Ident
    slice(hold, 6, strlen(hold)-2);
    if (isInTable(hold, table_global)) {        // 符号表操作
        printf("Ident exist!\n");
        exit(3);    // 语义错误
    }
    Ident *ident = (Ident *)malloc(sizeof(Ident));
    strcpy(ident->name, hold);
    strcpy(ident->type, "int");
    ident->address = ++register_cnt;
    ident->value = 0;
    ident->def = 0;
    insertItem(ident, table_global);
    fprintf(fp_out, "\t%%x%d = alloca i32\n", ident->address);

    memset(hold, '\0', sizeof(hold));
    fscanf(fp_in, "%s", hold);

    if (strcmp(hold, "Assign") == 0) {
        memset(hold, '\0', sizeof(hold));
        fscanf(fp_in, "%s", hold);
        Inter_var *result = analyseExp(fp_in, fp_out, 0);
        ident->value = result->value;
        if (result->reg == -1) { fprintf(fp_out, "\tstore i32 %d, i32* %%x%d\n", result->value, ident->address);}
        else { fprintf(fp_out, "\tstore i32 %%x%d, i32* %%x%d\n", result->reg, ident->address); }
    }
}

void analyseStmt(FILE *fp_in, FILE *fp_out) {
    // return
    if (strcmp(hold, "Return") == 0) {
        memset(hold, '\0', sizeof(hold));
        fscanf(fp_in, "%s", hold);

        // Exp
        Inter_var *result = analyseExp(fp_in, fp_out, 0);
        if (result->reg == -1) {
            fprintf(fp_out, "\tret i32 %d\n", result->value);
        } else {
            fprintf(fp_out, "\tret i32 %%x%d\n", result->reg);
        }
    } 
    // Func
    else if (isFuncBegin(hold)) {
        char temp[MAXLEN];
        strcpy(temp, hold);
        memset(hold, '\0', sizeof(hold));
        fscanf(fp_in, "%s", hold);
        Inter_var *result = analyseFuction(fp_in, fp_out, temp);
        memset(hold, '\0', sizeof(hold));
        fscanf(fp_in, "%s", hold);
    }
    // Ident
    else if (isIdentBegin(hold)) {
        slice(hold, 6, strlen(hold)-2);
        Ident *ident = findGlobalItem(hold, table_global);
        if (ident == NULL) {
            printf("Must be declared!\n");
            exit(3);    // 语义错误
        }
        if (ident->def == 1) {
            printf("Must be Var!\n");
            exit(3);    // 语义错误
        } 
        memset(hold, '\0', sizeof(hold));
        fscanf(fp_in, "%s", hold);

        // '='
        if (strcmp(hold, "Assign") != 0) {
            printf("Assign must!\n");
            exit(2);    // 语法错误
        }
        memset(hold, '\0', sizeof(hold));
        fscanf(fp_in, "%s", hold);

        // Exp
        Inter_var *result = analyseExp(fp_in, fp_out, 0);
        ident->value = result->value;
        if (ident->def == 3) {
            if (result->reg == -1) { fprintf(fp_out, "\tstore i32 %d, i32* @%s\n", result->value, ident->name);}
            else { fprintf(fp_out, "\tstore i32 %%x%d, i32* @%s\n", result->reg, ident->name); }
        } else {
            if (result->reg == -1) { fprintf(fp_out, "\tstore i32 %d, i32* %%x%d\n", result->value, ident->address);}
            else { fprintf(fp_out, "\tstore i32 %%x%d, i32* %%x%d\n", result->reg, ident->address); }
        }
    }
    // Block
    else if (strcmp(hold, "LBrace") == 0) {
        analyseBlock(fp_in, fp_out, 0);
        return;
    }
    // If
    else if (strcmp(hold, "If") == 0) {
        memset(hold, '\0', sizeof(hold));
        fscanf(fp_in, "%s", hold);

        // '('
        if (strcmp(hold, "LPar") != 0) {
            exit(2);    // 语法错误
        }
        memset(hold, '\0', sizeof(hold));
        fscanf(fp_in, "%s", hold);
        
        // cond
        Inter_var *result = analyseCond(fp_in, fp_out);
        fprintf(fp_out, "\tbr i1 %%x%d, label %%x%d, label %%x%d\n", result->reg_i1, register_cnt+1, register_cnt+2);

        // ')'
        if (strcmp(hold, "RPar") != 0) {
            exit(2);    // 语法错误
        }
        memset(hold, '\0', sizeof(hold));
        fscanf(fp_in, "%s", hold);

        int begin_if = ++register_cnt;
        int begin_else = ++register_cnt;
        int end = ++register_cnt;
        
        // Stmt
        fprintf(fp_out, "\nx%d:\n", begin_if);
        analyseStmt(fp_in, fp_out);
        fprintf(fp_out, "\tbr label %%x%d\n", end);
        
        // Else
        if (strcmp(hold, "Else") == 0) {
            memset(hold, '\0', sizeof(hold));
            fscanf(fp_in, "%s", hold);

            // Stmt
            fprintf(fp_out, "\nx%d:\n", begin_else);
            analyseStmt(fp_in, fp_out);
            fprintf(fp_out, "\tbr label %%x%d\n", end);

        } else {
            fprintf(fp_out, "\nx%d:\n", begin_else);
            fprintf(fp_out, "\tbr label %%x%d\n", end);
        }
        fprintf(fp_out, "\nx%d:\n", end);
        return;
    }
    // Exp
    else {
        Inter_var *result = analyseExp(fp_in, fp_out, 0);
    }

    // ';'
    if (strcmp(hold, "Semicolon") != 0) {
        exit(2);   // 语法错误
    }
    memset(hold, '\0', sizeof(hold));
    fscanf(fp_in, "%s", hold);
}

Inter_var *analyseCond(FILE *fp_in, FILE *fp_out) {
    Inter_var *result = analyseLOrExp(fp_in, fp_out);
}

Inter_var *analyseLOrExp(FILE *fp_in, FILE *fp_out) {
    Inter_var *result = analyseLAndExp(fp_in, fp_out);

    while (strcmp(hold, "Or") == 0) {
        memset(hold, '\0', sizeof(hold));
        fscanf(fp_in, "%s", hold);
        Inter_var *result_temp = analyseLOrExp(fp_in, fp_out);

        // LLVM
        printCondLLVM(fp_out, "or", result, result_temp);
    }

    return result;
}

Inter_var *analyseLAndExp(FILE *fp_in, FILE *fp_out) {
    Inter_var *result = analyseEqExp(fp_in, fp_out);

    while (strcmp(hold, "And") == 0) {
        memset(hold, '\0', sizeof(hold));
        fscanf(fp_in, "%s", hold);
        Inter_var *result_temp = analyseLAndExp(fp_in, fp_out);

        // LLVM
        printCondLLVM(fp_out, "and", result, result_temp);
    }

    return result;
}

Inter_var *analyseEqExp(FILE *fp_in, FILE *fp_out) {
    Inter_var *result = analyseRelExp(fp_in, fp_out);

    while (strcmp(hold, "Eq") == 0 || strcmp(hold, "NotEq") == 0) {
        // 缓存
        char temp[MAXLEN];
        memset(temp, '\0', sizeof(temp));
        strcpy(temp, hold);

        // 递归
        memset(hold, '\0', sizeof(hold));
        fscanf(fp_in, "%s", hold);
        Inter_var *result_temp = analyseEqExp(fp_in, fp_out);

        // LLVM
        if (strcmp(temp, "Eq") == 0) {
            printCondLLVM(fp_out, "eq", result, result_temp);
        }
        if (strcmp(temp, "NotEq") == 0) {
            printCondLLVM(fp_out, "ne", result, result_temp);
        }
    }

    // 强制类型转换，向上层提供i1数据类型
    if (result->reg_i1 == -1) {
        if (result->reg == -1) {fprintf(fp_out, "\t%%x%d = icmp ne i32 %d, 0\n", ++register_cnt, result->value);}
        else {fprintf(fp_out, "\t%%x%d = icmp ne i32 %%x%d, 0\n", ++register_cnt, result->reg);}

        result->reg_i1 = register_cnt;
    }
    return result;
}

Inter_var *analyseRelExp(FILE *fp_in, FILE *fp_out) {
    Inter_var *result = analyseExp(fp_in, fp_out, 2);

    while (strcmp(hold, "Great") == 0 || strcmp(hold, "GreatEq") == 0 || strcmp(hold, "Less") == 0 || strcmp(hold, "LessEq") == 0) {
        // 缓存
        char temp[MAXLEN];
        memset(temp, '\0', sizeof(temp));
        strcpy(temp, hold);

        // 递归
        memset(hold, '\0', sizeof(hold));
        fscanf(fp_in, "%s", hold);
        Inter_var *result_temp = analyseRelExp(fp_in, fp_out);

        // LLVM
        if (strcmp(temp, "Great") == 0) {
            printCondLLVM(fp_out, "sgt", result, result_temp);
        }
        if (strcmp(temp, "GreatEq") == 0) {
            printCondLLVM(fp_out, "sge", result, result_temp);
        }
        if (strcmp(temp, "Less") == 0) {
            printCondLLVM(fp_out, "slt", result, result_temp);
        }
        if (strcmp(temp, "LessEq") == 0) {
            printCondLLVM(fp_out, "sle", result, result_temp);
        }
    }

    return result;
}

void printCondLLVM(FILE *fp_out, char *str, Inter_var *a, Inter_var *b) {
    if (strcmp(str, "or")==0 || strcmp(str, "and")==0) {
        fprintf(fp_out, "\t%%x%d = %s i1 %%x%d, %%x%d\n", ++register_cnt, str, a->reg_i1, b->reg_i1);
        a->reg_i1 = register_cnt;
        if (strcmp(str, "or")==0 && b->value == 1) {
            a->value = 1;
        }
        if (strcmp(str, "and")==0 && b->value == 0) {
            a->value = 0;
        }
    }
    else if (strcmp(str, "eq")==0 || strcmp(str, "ne")==0) {
        if (a->reg == -1 && b->reg == -1) {
            fprintf(fp_out, "\t%%x%d = icmp %s i32 %d, %d\n", ++register_cnt, str, a->value, b->value);
        }
        else if (a->reg != -1 && b->reg == -1) {
            fprintf(fp_out, "\t%%x%d = icmp %s i32 %%x%d, %d\n", ++register_cnt, str, a->reg, b->value);
        }
        else if (a->reg == -1 && b->reg != -1) {
            fprintf(fp_out, "\t%%x%d = icmp %s i32 %d, %%x%d\n", ++register_cnt, str, a->value, b->reg);
        }
        else {
            fprintf(fp_out, "\t%%x%d = icmp %s i32 %%x%d, %%x%d\n", ++register_cnt, str, a->reg, b->reg);
        }
        
        a->reg_i1 = register_cnt;
        
        
        if (strcmp(str, "eq")==0 && b->value == a->value) {
            a->value = 1;
        } else {
            a->value = 0;
        }
        if (strcmp(str, "ne")==0 && b->value != a->value) {
            a->value = 1;
        } else {
            a->value = 0;
        }
    }
    else if (strcmp(str, "sgt") == 0 || strcmp(str, "sge") == 0 || strcmp(str, "slt") == 0 || strcmp(str, "sle") == 0) {
        if (a->reg == -1 && b->reg == -1) {
            fprintf(fp_out, "\t%%x%d = icmp %s i32 %d, %d\n", ++register_cnt, str, a->value, b->value);
        }
        else if (a->reg != -1 && b->reg == -1) {
            fprintf(fp_out, "\t%%x%d = icmp %s i32 %%x%d, %d\n", ++register_cnt, str, a->reg, b->value);
        }
        else if (a->reg == -1 && b->reg != -1) {
            fprintf(fp_out, "\t%%x%d = icmp %s i32 %d, %%x%d\n", ++register_cnt, str, a->value, b->reg);
        }
        else {
            fprintf(fp_out, "\t%%x%d = icmp %s i32 %%x%d, %%x%d\n", ++register_cnt, str, a->reg, b->reg);
        }

        a->reg_i1 = register_cnt;
        fprintf(fp_out, "\t%%x%d = zext i1 %%x%d to i32\n", ++register_cnt, a->reg_i1);
        a->reg = register_cnt;

        // 维护value
        if (strcmp(str, "sgt")==0 && a->value > b->value) {
            a->value = 1;
        } else {
            a->value = 0;
        }
        if (strcmp(str, "sge")==0 && a->value >= b->value) {
            a->value = 1;
        } else {
            a->value = 0;
        }
        if (strcmp(str, "slt")==0 && a->value < b->value) {
            a->value = 1;
        } else {
            a->value = 0;
        }
        if (strcmp(str, "sle")==0 && a->value <= b->value) {
            a->value = 1;
        } else {
            a->value = 0;
        }
    }
}

Inter_var *analyseFuction(FILE *fp_in, FILE *fp_out, char name[]) {
    slice(name, 6, strlen(name)-2);
    Inter_func *func;
    func = (Inter_func *)malloc(sizeof(Inter_func));
    strcpy(func->name, name);
    func->para_num = 0;

    memset(hold, '\0', sizeof(hold));
    fscanf(fp_in, "%s", hold);

    // 参数获取
    if (strcmp(hold, "RPar") != 0) {
        func->para_list[func->para_num++] = analyseExp(fp_in, fp_out, 2);

        while (strcmp(hold, "Comma") == 0) {
            memset(hold, '\0', sizeof(hold));
            fscanf(fp_in, "%s", hold);
            func->para_list[func->para_num++] = analyseExp(fp_in, fp_out, 2);
        }

        if (strcmp(hold, "RPar") != 0) {
            printf("Function no par!\n");
            exit(2);    // 语法错误
        }
    }
    
    Inter_var *ans;
    ans = (Inter_var *)malloc(sizeof(Inter_var));
    // 函数匹配
    if (strcmp(func->name, "getint") == 0) {
        if (func->para_num != 0) {
            printf("Parameters num wrong!\n");
            exit(3);    // 语义错误
        } 
        fprintf(fp_out, "\t%%x%d = call i32 @getint()\n", ++register_cnt);
        ans->reg = register_cnt;
        ans->value = 1;
        return ans;
    }
    else if (strcmp(func->name, "getch") == 0) {
        if (func->para_num != 0) {
            printf("Parameters num wrong!\n");
            exit(3);    // 语义错误
        } 
        fprintf(fp_out, "\t%%x%d = call i32 @getch()\n", ++register_cnt);
        ans->reg = register_cnt;
        ans->value = 1;
        return ans;
    }
    else if (strcmp(func->name, "putint") == 0) {
        if (func->para_num != 1) {
            printf("Parameters num wrong!\n");
            exit(3);    // 语义错误
        }
        if (func->para_list[0]->reg != -1) {
            fprintf(fp_out, "\tcall void @putint(i32 %%x%d)\n", func->para_list[0]->reg);
        } else {
            fprintf(fp_out, "\tcall void @putint(i32 %d)\n", func->para_list[0]->value);
        }
        
        return NULL;
    }
    else if (strcmp(func->name, "putch") == 0) {
        if (func->para_num != 1) {
            printf("Parameters num wrong!\n");
            exit(3);    // 语义错误
        }
        if (func->para_list[0]->reg != -1) {
            fprintf(fp_out, "\tcall void @putch(i32 %%x%d)\n", func->para_list[0]->reg);
        } else {
            fprintf(fp_out, "\tcall void @putch(i32 %d)\n", func->para_list[0]->value);
        }
        return NULL;
    } 
    else {
        printf("Function not define!\n");
        exit(3);    // 语义错误 
    } 
}

Inter_var *analyseExp(FILE *fp_in, FILE *fp_out, int mode) {
    // 初始化
    enum operator operators[MAXLEN];
    int top_opt = -1;
    Inter_var vars[MAXLEN];
    int top_var = -1;
    memset(operators, 0, sizeof(operators));
    memset(vars, 0, sizeof(vars));
    operators[++top_opt] = Boundary;
    int flag_read = 1;   // 循环是否需要新读入 
    int flag_first = 1;  // 第一次不用读
    enum operator opt = Boundary;
    
    // 循环处理
    while (1) {
        // 读入字符
        if (flag_first) {
            flag_first = 0;
            enum operator pre = opt;
            opt = judgeOpt(hold, pre);
        }
        else if (flag_read) {
            // 备份上一个hold及opt
            char temp[MAXLEN];
            memset(temp, '\0', sizeof(temp));
            strcpy(temp, hold);
            enum operator pre = opt;
            // 读入新的
            memset(hold, '\0', sizeof(hold));
            fscanf(fp_in, "%s", hold);
            opt = judgeOpt(hold, pre);

            // 函数边界特殊判断
            if (mode == 2 && opt == RPar) {
                int flag = 1;
                for (int i=0; i<=top_opt; i++) {
                    if (operators[i] == LPar)
                        flag = 0;
                }
                if (flag) opt = Boundary;
            }

            // 出错情况特别判断
            if ((pre == Number || pre == Idt) && (opt == Idt || opt == Number)) {
                printf("wrong priority");
                exit(2);
            }

            // 函数情况特别判断
            if (pre == Idt && opt == LPar) {
                Inter_var *result = analyseFuction(fp_in, fp_out, temp);
                if (result == NULL) {
                    printf("Function returns void but to calculated in an exp!\n");
                    exit(3);    // 语义错误
                }
                else {
                    vars[++top_var].value = result->value;
                    vars[top_var].reg = result->reg;
                    flag_read = 1;
                    opt = Number;
                    continue;
                }
            } 
            
            // Ident延迟入栈
            if (pre == Idt) {
                // 运算数栈存入变量/常量的信息
                slice(temp, 6, strlen(temp)-2);
                Ident *i = findGlobalItem(temp, table_global);
                if (i == NULL) {
                    printTable(table_global);
                    printf("Must be declared!\n");
                    exit(3);    // 语义错误
                }
                else {
                    if (mode == 1 && i->def != 1) {
                        printf("Const defination error!\n");
                        exit(3);    // 语义错误
                    }
                    // 常量
                    if (i->def == 1) {
                        vars[++top_var].value = i->value;
                        vars[top_var].reg = -1;
                        vars[top_var].reg_i1 = -1;
                    }
                    // 全局变量
                    if (i->def == 3 && (mode == 0 || mode == 2)) {
                        vars[++top_var].value = i->value;
                        vars[top_var].reg = ++register_cnt;
                        vars[top_var].reg_i1 = -1;
                        fprintf(fp_out, "\t%%x%d = load i32, i32* @%s\n", register_cnt, i->name);
                    }
                    // 局部变量
                    if (i->def == 0 && (mode == 0 || mode == 2)) {
                        vars[++top_var].value = i->value;
                        vars[top_var].reg = ++register_cnt;
                        vars[top_var].reg_i1 = -1;
                        fprintf(fp_out, "\t%%x%d = load i32, i32* %%x%d\n", register_cnt, i->address);
                    }
                }
            }
        }

        // 分析结束
        if (opt == Boundary && operators[top_opt] == Boundary && top_var != -1) {
            printf("over: %d in %%x%d\n", vars[top_var].value, vars[top_var].reg);
            Inter_var *result;
            result = (Inter_var*)malloc(sizeof(Inter_var));
            result->reg = vars[top_var].reg;
            result->reg_i1 = -1;
            result->value = vars[top_var].value;
            return result;
        }

        // 优先级等于
        else if (priority[operators[top_opt]][opt] == 0) {
            if (top_var == -1 || operators[top_opt] != LPar) {
                printf("parenthesis error");
                exit(2);    // 语法错误
            }
            top_opt--;
            flag_read = 1;
        }
        
        // 优先级小于
        else if (priority[operators[top_opt]][opt] == 1) {
            // 数字常量
            if (opt == Number) {
                if (strncmp(hold, "Dec", 3) == 0) { 
                    slice(hold, 10, strlen(hold)-2); 
                    vars[++top_var].value = D2D(hold);
                    vars[top_var].reg = -1;
                    vars[top_var].reg_i1 = -1;
                }
                if (strncmp(hold, "Oct", 3) == 0) { 
                    slice(hold, 10, strlen(hold)-2);
                    vars[++top_var].value = O2D(hold);
                    vars[top_var].reg = -1; 
                    vars[top_var].reg_i1 = -1;
                }
                if (strncmp(hold, "Hex", 3) == 0) {
                    slice(hold, 10, strlen(hold)-2);
                    vars[++top_var].value = H2D(hold);
                    vars[top_var].reg = -1; 
                    vars[top_var].reg_i1 = -1;
                }           
            }
            // 定义的变量或常量
            else if (opt == Idt) {
                flag_read = 1;
                continue;
            } 
            // 运算符
            else {
                operators[++top_opt] = opt;
            }
            flag_read = 1;
        }

        // 优先级大于
        else if (priority[operators[top_opt]][opt] == 2) {
            specify(fp_out, mode, vars, &top_var, operators[top_opt--]);
            flag_read = 0;
        }

        // 出错
        else if (priority[operators[top_opt]][opt] == 3) {
            printf("Wrong priority\n");
            exit(2);    // 语法错误
        }
    }

    // 释放资源
    free(operators);
    free(vars);
}

enum operator judgeOpt(char str[], enum operator pre) {
    if (strcmp(str, "Plus") == 0) {
        if (pre == Number || pre == Idt || pre == RPar) {
            return Plus;
        } else {
            return UnPlus;
        }
    }
    if (strcmp(str, "Minus") == 0) {
        if (pre == Number || pre == Idt || pre == RPar) {
            return Minus;
        } else {
            return UnMinus;
        }
    }
    if (strcmp(str, "Mult") == 0) { return Mult; }
    if (strcmp(str, "Div") == 0) { return Div; }
    if (strcmp(str, "Rem") == 0) { return Rem; }
    if (strcmp(str, "LPar") == 0) { return LPar; }
    if (strcmp(str, "RPar") == 0) { return RPar; }
    if (strcmp(str, "Rev") == 0) { return Rev; }
    if (isNumber(hold)) { return Number; }
    if (isIdentBegin(hold)) { return Idt; }
    return Boundary;
}

void specify(FILE *fp_out, int mode, Inter_var vars[], int *top_var, enum operator opt) {
    // 双目运算
    if (opt != UnPlus && opt != UnMinus && opt != Rev) {
        // 运算数不够
        if (*top_var < 1) {
            printf("Vars not enough(bi)\n");
            exit(2);    // 语法错误 
        }
        // 运算
        Inter_var b = vars[(*top_var)--];
        Inter_var a = vars[(*top_var)--];
        if (opt == Plus) { 
            vars[++(*top_var)].value = a.value + b.value;
            if (mode != 1) { printLLVM(fp_out, vars, top_var, "add", a, b); }
            else { vars[*top_var].reg = -1; }
        }
        if (opt == Minus) { 
            vars[++(*top_var)].value = a.value - b.value;
            if (mode != 1) { printLLVM(fp_out, vars, top_var, "sub", a, b); }
            else { vars[*top_var].reg = -1; }
        }
        if (opt == Mult) { 
            vars[++(*top_var)].value = a.value * b.value;
            if (mode != 1) { printLLVM(fp_out, vars, top_var, "mul", a, b); }
            else { vars[*top_var].reg = -1; }
        }
        if (opt == Div) { 
            vars[++(*top_var)].value = a.value / b.value;
            if (mode != 1) { printLLVM(fp_out, vars, top_var, "sdiv", a, b); }
            else { vars[*top_var].reg = -1; }
        }
        if (opt == Rem) { 
            vars[++(*top_var)].value = a.value % b.value;
            if (mode != 1) { printLLVM(fp_out, vars, top_var, "srem", a, b); }
            else { vars[*top_var].reg = -1; }
        }
    }

    // 单目运算
    else {
        // 运算数不够
        if (*top_var == -1) { 
            printf("Vars not enough(un)\n"); 
            exit(2);    // 语法错误 
        }
        // 运算
        if (opt == UnMinus) {
            if (mode != 1) {
                Inter_var temp;
                temp.value = 0;
                temp.reg = -1;
                temp.reg_i1 = -1;
                printLLVM(fp_out, vars, top_var, "sub", temp, vars[*top_var]);
            }
            vars[*top_var].value *= -1;
        }
        else if (opt == Rev) {
            // LLVM
            if (vars[*top_var].reg == -1) {
                fprintf(fp_out, "\t%%x%d = icmp eq i32 %d, 0\n", ++register_cnt, vars[*top_var].value);
                vars[*top_var].reg_i1 = register_cnt;
            } else {
                if (vars[*top_var].reg_i1 == -1) {
                    fprintf(fp_out, "\t%%x%d = icmp eq i32 %%x%d, 0\n", ++register_cnt, vars[*top_var].reg);
                    vars[*top_var].reg_i1 = register_cnt;
                } else {
                    fprintf(fp_out, "\t%%x%d = icmp eq i1 %%x%d, 0\n", ++register_cnt, vars[*top_var].reg_i1);
                    vars[*top_var].reg_i1 = register_cnt;
                }
            }
            fprintf(fp_out, "\t%%x%d = zext i1 %%x%d to i32\n", ++register_cnt, vars[*top_var].reg_i1);
            vars[*top_var].reg = register_cnt;
            
            // value
            if (vars[*top_var].value != 0) {
                vars[*top_var].value = 0;
            } else {
                vars[*top_var].value = 1;
            }
        }
    }
}

void printLLVM(FILE *fp_out, Inter_var vars[], int *top_var, char *str, Inter_var a, Inter_var b) {
    vars[*top_var].reg = ++register_cnt;
    // i & i
    if (a.reg == -1 && b.reg == -1) {
        fprintf(fp_out, "\t%%x%d = %s i32 %d, %d\n", vars[*top_var].reg, str, a.value, b.value);
    }
    // %i & i
    if (a.reg != -1 && b.reg == -1) {
        fprintf(fp_out, "\t%%x%d = %s i32 %%x%d, %d\n", vars[*top_var].reg, str, a.reg, b.value);
    }
    // i & %i
    if (a.reg == -1 && b.reg != -1) {
        fprintf(fp_out, "\t%%x%d = %s i32 %d, %%x%d\n", vars[*top_var].reg, str, a.value, b.reg); 
    }
    // %i & %i
    if (a.reg != -1 && b.reg != -1) {
        fprintf(fp_out, "\t%%x%d = %s i32 %%x%d, %%x%d\n", vars[*top_var].reg, str, a.reg, b.reg);   
    }
}